﻿<!DOCTYPE html>
<!--[if IE]><![endif]-->
<html>
  
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title> </title>
    <meta name="viewport" content="width=device-width">
    <meta name="title" content=" ">
    <meta name="generator" content="docfx 2.56.6.0">
    
    <link rel="shortcut icon" href="../favicon.ico">
    <link rel="stylesheet" href="../styles/docfx.vendor.css">
    <link rel="stylesheet" href="../styles/docfx.css">
    <link rel="stylesheet" href="../styles/main.css">
    <meta property="docfx:navrel" content="../toc.html">
    <meta property="docfx:tocrel" content="toc.html">
    
    
    
  </head>
  <body data-spy="scroll" data-target="#affix" data-offset="120">
    <div id="wrapper">
      <header>
        
        <nav id="autocollapse" class="navbar navbar-inverse ng-scope" role="navigation">
          <div class="container">
            <div class="navbar-header">
              <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
              
              <a class="navbar-brand" href="../index.html">
                <img id="logo" class="svg" src="../logo.svg" alt="">
              </a>
            </div>
            <div class="collapse navbar-collapse" id="navbar">
              <form class="navbar-form navbar-right" role="search" id="search">
                <div class="form-group">
                  <input type="text" class="form-control" id="search-query" placeholder="Search" autocomplete="off">
                </div>
              </form>
            </div>
          </div>
        </nav>
        
        <div class="subnav navbar navbar-default">
          <div class="container hide-when-search" id="breadcrumb">
            <ul class="breadcrumb">
              <li></li>
            </ul>
          </div>
        </div>
      </header>
      <div role="main" class="container body-content hide-when-search">
        
        <div class="sidenav hide-when-search">
          <a class="btn toc-toggle collapse" data-toggle="collapse" href="#sidetoggle" aria-expanded="false" aria-controls="sidetoggle">Show / Hide Table of Contents</a>
          <div class="sidetoggle collapse" id="sidetoggle">
            <div id="sidetoc"></div>
          </div>
        </div>
        <div class="article row grid-right">
          <div class="col-md-10">
            <article class="content wrap" id="_content" data-uid="">

<p>This class is a work in progress. Samples coming soon. To use this, copy and paste the code and the other files in the folder in to your project. Nuget package does not contain this class.</p>
<p><a href="https://github.com/MelbourneDeveloper/Device.Net/blob/develop/src/Device.Net.Reactive/DeviceManager.cs">Code Reference</a></p>
<pre><code class="lang-cs">using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Device.Net
{
    /// &lt;summary&gt;
    /// This class is a work in progress. It is not production ready.
    /// &lt;/summary&gt;
    public class DeviceManager : IDeviceManager, IDisposable
    {
        #region Fields
        private readonly ILogger&lt;DeviceManager&gt; _logger;
        private readonly Func&lt;IDevice, Task&gt; _initializeDeviceAction;
        private IDevice _selectedDevice;
        private readonly Queue&lt;IRequest&gt; _queuedRequests = new Queue&lt;IRequest&gt;();
        private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
        private readonly SemaphoreSlim _semaphoreSlim2 = new SemaphoreSlim(1, 1);
        private readonly DeviceNotify _notifyDeviceInitialized;
        private readonly NotifyDeviceException _notifyDeviceException;
        private readonly DevicesNotify _notifyConnectedDevices;
        private bool isDisposed;
        private readonly int _pollMilliseconds;
        private readonly GetConnectedDevicesAsync _getConnectedDevicesAsync;
        private readonly GetDeviceAsync _getDevice;
        #endregion

        #region Public Properties
        /// &lt;summary&gt;
        /// Placeholder. Don't use. This functionality will be injected in
        /// &lt;/summary&gt;
        public bool FilterMiddleMessages { get; set; }

        public IObservable&lt;IReadOnlyCollection&lt;ConnectedDeviceDefinition&gt;&gt; ConnectedDevicesObservable { get; }

        public IDevice SelectedDevice
        {
            get =&gt; _selectedDevice;
            private set
            {
                _selectedDevice = value;
                _notifyDeviceInitialized(value?.ConnectedDeviceDefinition);
            }
        }
        #endregion

        #region Constructor
        /// &lt;summary&gt;
        /// 
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;notifyDeviceInitialized&quot;&gt;Tells others that the device was initialized&lt;/param&gt;
        /// &lt;param name=&quot;notifyConnectedDevices&quot;&gt;Tells others which devices are connected&lt;/param&gt;
        /// &lt;param name=&quot;notifyDeviceException&quot;&gt;&lt;/param&gt;
        /// &lt;param name=&quot;initializeDeviceAction&quot;&gt;&lt;/param&gt;
        /// &lt;param name=&quot;getConnectedDevicesAsync&quot;&gt;&lt;/param&gt;
        /// &lt;param name=&quot;getDevice&quot;&gt;&lt;/param&gt;
        /// &lt;param name=&quot;pollMilliseconds&quot;&gt;&lt;/param&gt;
        /// &lt;param name=&quot;loggerFactory&quot;&gt;&lt;/param&gt;
        public DeviceManager(
            DeviceNotify notifyDeviceInitialized,
            DevicesNotify notifyConnectedDevices,
            NotifyDeviceException notifyDeviceException,
            Func&lt;IDevice, Task&gt; initializeDeviceAction,
            GetConnectedDevicesAsync getConnectedDevicesAsync,
            GetDeviceAsync getDevice,
            int pollMilliseconds,
            ILoggerFactory loggerFactory = null)
        {
            _notifyDeviceInitialized = notifyDeviceInitialized ?? throw new ArgumentNullException(nameof(notifyDeviceInitialized));
            _notifyDeviceException = notifyDeviceException ?? throw new ArgumentNullException(nameof(notifyDeviceException));
            _notifyConnectedDevices = notifyConnectedDevices ?? throw new ArgumentNullException(nameof(notifyConnectedDevices));
            _getConnectedDevicesAsync = getConnectedDevicesAsync ?? throw new ArgumentNullException(nameof(getConnectedDevicesAsync));
            _getDevice = getDevice ?? throw new ArgumentNullException(nameof(getDevice));

            _logger = (loggerFactory ?? NullLoggerFactory.Instance).CreateLogger&lt;DeviceManager&gt;();

            _initializeDeviceAction = initializeDeviceAction;
            _pollMilliseconds = pollMilliseconds;
        }
        #endregion

        #region Public Methods
        public void Start()
        {
            _ = Task.Run(async () =&gt;
            {
                while (!isDisposed)
                {
                    var devices = await _getConnectedDevicesAsync();
                    _logger.LogInformation(&quot;Found {deviceCount} devices&quot;, devices.Count);
                    _notifyConnectedDevices(devices);
                    await Task.Delay(TimeSpan.FromMilliseconds(_pollMilliseconds));
                }
            });
        }

        /// &lt;summary&gt;
        /// Sets the selected device
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;connectedDevice&quot;&gt;&lt;/param&gt;
        public void SelectDevice(ConnectedDeviceDefinition connectedDevice)
        {
            _ = connectedDevice == null
                ? throw new ArgumentNullException(nameof(connectedDevice))
                : InitializeDeviceAsync(connectedDevice);
        }

        public async Task&lt;TResponse&gt; WriteAndReadAsync&lt;TResponse&gt;(IRequest request, Func&lt;byte[], TResponse&gt; convertFunc)
        {
            if (SelectedDevice == null) return default;
            if (request == null) throw new ArgumentNullException(nameof(request));

            try
            {
                await _semaphoreSlim.WaitAsync();
                var writeBuffer = request.ToArray();
                var readBuffer = await SelectedDevice.WriteAndReadAsync(writeBuffer);
                return convertFunc != null ? convertFunc(readBuffer) : default;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);

                if (ex is not IOException) throw;

                _notifyDeviceException(SelectedDevice?.ConnectedDeviceDefinition, ex);
                //The exception was an IO exception so disconnect the device
                //The listener should reconnect

                SelectedDevice.Dispose();

                SelectedDevice = null;

                throw;
            }
            finally
            {
                _ = _semaphoreSlim.Release();
            }
        }

        public void QueueRequest(IRequest request)
        {
            //If ther is no device selected just eat up the messages
            if (SelectedDevice == null) return;

            if (request == null) throw new ArgumentNullException(nameof(request));

            _queuedRequests.Enqueue(request);
            _ = ProcessQueue();
        }

        private async Task ProcessQueue()
        {
            try
            {
                await _semaphoreSlim2.WaitAsync();

                IRequest mostRecentRequest = null;

                if (_queuedRequests.Count == 0) return;

                if (FilterMiddleMessages)
                {
                    //Eat requests except for the most recent one
                    while (_queuedRequests.Count &gt; 0)
                    {
                        mostRecentRequest = _queuedRequests.Dequeue();
                    }
                }

                _ = await WriteAndReadAsync&lt;object&gt;(mostRecentRequest, null);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
            }
            finally
            {
                _ = _semaphoreSlim2.Release();
            }
        }
        #endregion

        #region Private Methods
        private async Task InitializeDeviceAsync(ConnectedDeviceDefinition connectedDevice)
        {
            try
            {
                if (connectedDevice == null)
                {
                    _logger.LogInformation(&quot;Initialize requested but device was null&quot;);
                    SelectedDevice = null;
                    return;
                }

                var device = await _getDevice(connectedDevice);
                await _initializeDeviceAction(device);

                _logger.LogInformation(&quot;Device initialized {deviceId}&quot;, connectedDevice.DeviceId);
                SelectedDevice = device;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
                _notifyDeviceException(connectedDevice, ex);
                SelectedDevice = null;
            }
        }

        public void Dispose()
        {
            isDisposed = true;
            _semaphoreSlim.Dispose();
            _semaphoreSlim2.Dispose();
        }
        #endregion
    }
}
</code></pre>
</article>
          </div>
          
          <div class="hidden-sm col-md-2" role="complementary">
            <div class="sideaffix">
              <div class="contribution">
                <ul class="nav">
                  <li>
                    <a href="https://github.com/MelbourneDeveloper/Device.Net/blob/develop/docfx_project/articles/DeviceManager.md/#L1" class="contribution-link">Improve this Doc</a>
                  </li>
                </ul>
              </div>
              <nav class="bs-docs-sidebar hidden-print hidden-xs hidden-sm affix" id="affix">
                <h5>In This Article</h5>
                <div></div>
              </nav>
            </div>
          </div>
        </div>
      </div>
      
      <footer>
        <div class="grad-bottom"></div>
        <div class="footer">
          <div class="container">
            <span class="pull-right">
              <a href="#top">Back to top</a>
            </span>
            
            <span>Generated by <strong>DocFX</strong></span>
          </div>
        </div>
      </footer>
    </div>
    
    <script type="text/javascript" src="../styles/docfx.vendor.js"></script>
    <script type="text/javascript" src="../styles/docfx.js"></script>
    <script type="text/javascript" src="../styles/main.js"></script>
  </body>
</html>
